package com.travelgroup.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.travelgroup.constant.RedisConstant;
import com.travelgroup.domain.dto.ItineraryDTO;
import com.travelgroup.domain.dto.ScheduleDTO;
import com.travelgroup.domain.entity.Itinerary;
import com.travelgroup.domain.vo.ItineraryVO;
import com.travelgroup.exception.BusinessException;
import com.travelgroup.mapper.ItineraryMapper;
import com.travelgroup.service.IItineraryService;
import com.travelgroup.service.IScheduleService;
import com.travelgroup.utils.RedisUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class ItineraryServiceImpl extends ServiceImpl<ItineraryMapper, Itinerary>
        implements IItineraryService {
    @Resource
    private IScheduleService scheduleService;
    @Resource
    private RedisUtil redisUtil;

    /**
     * 存储总行程信息
     * @param itineraryDTO
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void saveItinerary(ItineraryDTO itineraryDTO) {
        // 检查每日行程是否为空
        List<ScheduleDTO> schedules = itineraryDTO.getSchedules();
        if (schedules == null || schedules.isEmpty()) {
            throw new BusinessException("每日行程不能为空");
        }

        // 保存总行程
        Itinerary itinerary = BeanUtil.copyProperties(itineraryDTO, Itinerary.class);
        if (!this.save(itinerary)) {
            throw new BusinessException("存储总行程信息失败");
        }

        // 为每日行程关联总行程
        schedules.forEach(schedule -> schedule.setItineraryId(itinerary.getId()));
        scheduleService.saveSchedules(schedules);
        redisUtil.removeById(RedisConstant.ITINERARY_KEY, itinerary.getId());
    }

    /**
     * 获取总行程信息
     * @param id
     * @return
     */
    @Override
    public ItineraryVO queryItinerary(Long id) {
        // 检查是否存在总行程
        Itinerary itinerary = getByRedis(id);
        if (itinerary == null) {
            throw new BusinessException("数据库数据错误");
        }

        // 获取总行程
        ItineraryVO itineraryVO = BeanUtil.copyProperties(itinerary, ItineraryVO.class);
        scheduleService.queryItinerarySummery(itinerary.getId(), itineraryVO);
        return itineraryVO;
    }

    /**
     * 删除总行程信息
     * @param id
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deleteItinerary(Long id) {
        // 查询并检查总行程是否存在
        Itinerary itinerary = this.getById(id);
        if (itinerary == null) {
            throw new BusinessException("数据库数据错误");
        }
        Long itineraryId = itinerary.getId();
        if (!this.removeById(id)) {
            throw new BusinessException("删除行程信息失败");
        }

        // 删除全部行程
        scheduleService.deleteSchedule(itineraryId);
        redisUtil.removeById(RedisConstant.ITINERARY_KEY, itinerary.getId());
    }

    /**
     * 更新总行程
     * @param id
     * @param itineraryDTO
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateItinerary(Long id, ItineraryDTO itineraryDTO) {
        // 获取总行程并检查是否存在
        Itinerary itinerary = this.getById(id);
        if (itinerary == null) {
            throw new BusinessException("数据库数据错误");
        }
        // 更新总行程信息
        BeanUtil.copyProperties(itineraryDTO, itinerary);
        if (!this.updateById(itinerary)) {
            throw new BusinessException("行程信息修改失败");
        }
        redisUtil.removeById(RedisConstant.ITINERARY_KEY, itinerary.getId());
    }

    /**
     * id查询总行程
     * @param id
     * @return
     */
    @Override
    public Itinerary getByRedis(Long id) {
        return redisUtil.queryById(RedisConstant.ITINERARY_KEY, id, Itinerary.class,
                i -> this.lambdaQuery()
                        .eq(Itinerary::getGroupId, i)
                        .one()
                , RedisConstant.CACHE_TTL, TimeUnit.MINUTES);
    }
}
